<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>点阵屏显示</title>
    <script src="mqtt.min.js"></script>
    <style>
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #0f2027, #203a43, #2c5364);
            color: white;
            min-height: 100vh;
            /* padding: 20px; */
            display: flex;
            flex-direction: column;
            cursor: none;
        }

        .header {
            text-align: center;
            margin-bottom: 25px;
            padding: 15px;
            background: rgba(0, 0, 0, 0.4);
            border-radius: 15px;
            box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
            display: none;
        }

        h1 {
            font-size: 2.2rem;
            margin-bottom: 10px;
            text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
        }

        .subtitle {
            font-size: 1rem;
            opacity: 0.9;
        }

        .main-content {
            display: flex;
            flex-direction: column;
            /* gap: 20px;
            max-width: 1200px; */
            margin: 0 auto;
            width: 100%;
        }

        .matrix-container {
            background: rgba(0, 0, 0, 0.6);
            /* padding: 25px; */
            border-radius: 15px;
            box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
            display: flex;
            justify-content: center;
            align-items: center;
            /* min-height: 500px; */
            min-width: 100vw;
            min-height: 100vh;
            flex: 1;
        }

        .matrix {
            display: grid;
            gap: 2px;
            background: #000;
            padding: 15px;
            border-radius: 10px;
            box-shadow: inset 0 0 30px rgba(0, 0, 0, 0.9);
        }

        .cell {
            width: 25px;
            height: 25px;
            background: #1a1a1a;
            border-radius: 4px;
            transition: all 0.1s ease;
        }

        .status-panel {
            background: rgba(0, 0, 0, 0.5);
            padding: 20px;
            border-radius: 15px;
            box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
            display: none;
        }

        .status-title {
            font-size: 1.3rem;
            margin-bottom: 15px;
            color: #4a90e2;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .status-info {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            margin-bottom: 15px;
        }

        .info-item {
            background: rgba(255, 255, 255, 0.1);
            padding: 12px;
            border-radius: 8px;
        }

        .info-label {
            font-size: 0.9rem;
            opacity: 0.8;
            margin-bottom: 5px;
        }

        .info-value {
            font-size: 1.1rem;
            font-weight: bold;
        }

        .log-container {
            background: rgba(0, 0, 0, 0.3);
            padding: 15px;
            border-radius: 8px;
            max-height: 120px;
            overflow-y: auto;
            font-family: monospace;
            font-size: 0.9rem;
        }

        .connection-status {
            display: inline-block;
            width: 12px;
            height: 12px;
            border-radius: 50%;
            margin-right: 8px;
        }

        .connected {
            background: #4caf50;
            box-shadow: 0 0 10px #4caf50;
        }

        .disconnected {
            background: #f44336;
        }

        @media (max-width: 768px) {
            .matrix-container {
                /* min-height: 400px;
                padding: 15px; */
            }

            .cell {
                width: 20px;
                height: 20px;
            }
        }
    </style>
</head>

<body>
    <div class="header">
        <h1>点阵屏显示</h1>
        <p class="subtitle">接收MQTT命令并显示点阵内容</p>
    </div>

    <div class="main-content">
        <div class="matrix-container">
            <div class="matrix" id="matrix"></div>
        </div>

        <div class="status-panel">
            <div class="status-title">
                <span>状态信息</span>
                <span id="connectionStatus" class="connection-status disconnected"></span>
            </div>

            <div class="status-info">
                <div class="info-item">
                    <div class="info-label">点阵尺寸</div>
                    <div class="info-value" id="matrixSize">0x0</div>
                </div>
                <div class="info-item">
                    <div class="info-label">MQTT Broker</div>
                    <div class="info-value" id="brokerInfo">未连接</div>
                </div>
                <div class="info-item">
                    <div class="info-label">命令主题</div>
                    <div class="info-value" id="commandTopicInfo">-</div>
                </div>
                <div class="info-item">
                    <div class="info-label">数据主题</div>
                    <div class="info-value" id="dataTopicInfo">-</div>
                </div>
            </div>

            <div class="log-container" id="statusLog">
                等待连接...
            </div>
        </div>
    </div>

    <script>
        // 全局变量
        let client = null;
        let matrix = [];
        let rows = 0;
        let cols = 0;
        let currentConfig = {
            broker: `ws://${location.hostname}:8083/mqtt`,
            clientId: 'matrix-display-' + Math.random().toString(36).substr(2, 9),
            commandTopic: 'matrix/command',
            dataTopic: 'matrix/data'
        };

        // DOM 元素
        const matrixEl = document.getElementById('matrix');
        const statusLog = document.getElementById('statusLog');
        const connectionStatus = document.getElementById('connectionStatus');
        const matrixSize = document.getElementById('matrixSize');
        const brokerInfo = document.getElementById('brokerInfo');
        const commandTopicInfo = document.getElementById('commandTopicInfo');
        const dataTopicInfo = document.getElementById('dataTopicInfo');

        // 初始化
        function init() {
            // 从URL参数获取配置（可选）
            const urlParams = new URLSearchParams(window.location.search);
            if (urlParams.has('broker')) currentConfig.broker = urlParams.get('broker');
            if (urlParams.has('clientId')) currentConfig.clientId = urlParams.get('clientId');
            if (urlParams.has('commandTopic')) currentConfig.commandTopic = urlParams.get('commandTopic');
            if (urlParams.has('dataTopic')) currentConfig.dataTopic = urlParams.get('dataTopic');

            // 更新UI信息
            brokerInfo.textContent = currentConfig.broker;
            commandTopicInfo.textContent = currentConfig.commandTopic;
            dataTopicInfo.textContent = currentConfig.dataTopic;

            // 自动连接
            setTimeout(connectMQTT, 1000);
        }

        // 创建点阵
        function createMatrix(newRows, newCols, cell_size = 25) {
            // if (newRows === rows && newCols === cols) return;

            rows = newRows;
            cols = newCols;

            let gap = 2
            let padding = 15
            let width = padding * 2 + cell_size * newCols + gap * (newCols - 1)
            let height = padding * 2 + cell_size * newRows + gap * (newRows - 1)

            const innerWidth = document.body.clientWidth
            const innerHeight = document.body.clientHeight
            if (width > innerWidth || height > innerHeight) {
                logStatus(`分辨率${width}x${height}超出最大支持范围${innerWidth}x${innerHeight}`);
                return
            }

            matrix = [];
            matrixEl.innerHTML = '';
            matrixEl.style.gridTemplateColumns = `repeat(${cols}, 1fr)`;
            matrixSize.textContent = `${rows}x${cols}`;

            for (let i = 0; i < rows; i++) {
                matrix[i] = [];
                for (let j = 0; j < cols; j++) {
                    const cell = document.createElement('div');
                    cell.className = 'cell';
                    cell.dataset.row = i;
                    cell.dataset.col = j;
                    cell.style.width = `${cell_size}px`
                    cell.style.height = `${cell_size}px`
                    matrixEl.appendChild(cell);
                    matrix[i][j] = '#1a1a1a';
                }
            }

            logStatus(`创建了 ${rows}x${cols} 的点阵, 分辨率${width}x${height}`);
        }

        // 设置单元格颜色
        function setCellColor(row, col, color) {
            if (row >= 0 && row < rows && col >= 0 && col < cols) {
                matrix[row][col] = color;
                const cell = document.querySelector(`.cell[data-row="${row}"][data-col="${col}"]`);
                if (cell) {
                    cell.style.backgroundColor = color;
                }
            }
        }

        // 清除屏幕
        function clearMatrix() {
            for (let i = 0; i < rows; i++) {
                for (let j = 0; j < cols; j++) {
                    setCellColor(i, j, '#1a1a1a');
                }
            }
            logStatus('屏幕已清除');
        }

        // 显示图像数据
        function displayImage(startRow, startCol, imageData) {
            if (!Array.isArray(imageData)) {
                logStatus('错误: 图像数据必须是二维数组');
                return;
            }

            for (let i = 0; i < imageData.length; i++) {
                if (!Array.isArray(imageData[i])) continue;

                for (let j = 0; j < imageData[i].length; j++) {
                    const row = startRow + i;
                    const col = startCol + j;

                    if (row >= 0 && row < rows && col >= 0 && col < cols) {
                        setCellColor(row, col, imageData[i][j]);
                    }
                }
            }

            logStatus(`显示图像: 从(${startRow},${startCol})开始`);
        }

        // 连接MQTT
        function connectMQTT() {
            try {
                client = mqtt.connect(currentConfig.broker, {
                    clientId: currentConfig.clientId,
                    clean: true,
                    connectTimeout: 4000,
                    reconnectPeriod: 1000,
                });

                client.on('connect', () => {
                    logStatus('MQTT连接成功');
                    connectionStatus.className = 'connection-status connected';
                    createMatrix(32, 64, 25)
                    // 订阅主题
                    client.subscribe(currentConfig.commandTopic, (err) => {
                        if (err) {
                            logStatus(`订阅命令主题失败: ${err}`);
                        } else {
                            logStatus(`已订阅命令主题: ${currentConfig.commandTopic}`);
                        }
                    });

                    client.subscribe(currentConfig.dataTopic, (err) => {
                        if (err) {
                            logStatus(`订阅数据主题失败: ${err}`);
                        } else {
                            logStatus(`已订阅数据主题: ${currentConfig.dataTopic}`);
                        }
                    });
                });

                client.on('message', (topic, message) => {
                    try {
                        const data = JSON.parse(message.toString());
                        logStatus(`收到消息 [${topic}]: ${message.toString().substring(0, 100)}...`);

                        if (topic === currentConfig.commandTopic) {
                            handleCommand(data);
                        } else if (topic === currentConfig.dataTopic) {
                            handleData(data);
                        }
                    } catch (e) {
                        logStatus(`解析消息失败: ${e.message}`);
                    }
                });

                client.on('error', (error) => {
                    logStatus(`MQTT连接错误: ${error.message}`);
                    connectionStatus.className = 'connection-status disconnected';
                });

                client.on('close', () => {
                    logStatus('MQTT连接已断开');
                    connectionStatus.className = 'connection-status disconnected';
                });

            } catch (error) {
                logStatus(`MQTT连接失败: ${error.message}`);
                connectionStatus.className = 'connection-status disconnected';
            }
        }

        // 处理命令
        function handleCommand(command) {
            if (!command.type) {
                logStatus('无效命令: 缺少type字段');
                return;
            }

            switch (command.type) {
                case 'config':
                    // 接收配置命令，设置点阵大小
                    if (command.rows && command.cols) {
                        createMatrix(command.rows, command.cols, command.cell_size);
                    }
                    break;

                case 'set':
                    if (command.row !== undefined && command.col !== undefined && command.color) {
                        setCellColor(command.row, command.col, command.color);
                    }
                    break;

                case 'image':
                    if (command.startRow !== undefined && command.startCol !== undefined && command.data) {
                        displayImage(command.startRow, command.startCol, command.data);
                    }
                    break;

                case 'clear':
                    clearMatrix();
                    break;

                default:
                    logStatus(`未知命令类型: ${command.type}`);
            }
        }

        // 处理数据
        function handleData(data) {
            if (Array.isArray(data)) {
                // 如果还没有创建矩阵，先创建一个合适的大小
                if (rows === 0 || cols === 0) {
                    const maxRows = data.length;
                    const maxCols = Math.max(...data.map(row => Array.isArray(row) ? row.length : 0));
                    createMatrix(Math.max(maxRows, 8), Math.max(maxCols, 8));
                }
                displayImage(0, 0, data);
            }
        }

        // 日志状态
        function logStatus(message) {
            const timestamp = new Date().toLocaleTimeString();
            const logEntry = `[${timestamp}] ${message}`;
            console.log(logEntry)
            return
            statusLog.innerHTML = logEntry + '<br>' + statusLog.innerHTML;

            // 限制日志行数
            const logLines = statusLog.innerHTML.split('<br>');
            if (logLines.length > 10) {
                statusLog.innerHTML = logLines.slice(0, 10).join('<br>');
            }
        }

        // 初始化应用
        window.addEventListener('DOMContentLoaded', init);
    </script>
</body>

</html>